package org.demo.base.proxy.cglibproxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * Cglib代理实现步骤：
 *  1.创建被代理对象
 *  2.创建Enhancer对象
 *  3.为Enhancer设置回调 MethodInterceptor实现
 *  4.Enhancer.create()生成代理对象
 *
 *
 *  总结：Cglib代理不需要被代理对象有接口，Cglib生成的代理对象是给被代理对象一个子对象，可理解为Cglib代理生成了一个被代理
 *      类的子类
 *
 *      Cglib借助Enhancer对象生成代理对象
 *      Enhancer对象在生成代理对象时需要设置一个回调Callback,一般使用MethodInterceptor的实现
 *      最后再为Enhancer对象设置被代理对象的class,Enhancer.create()生成代理对象
 *
 *  参数：
 *       public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)
 *
 *
 *      Object 生成的代理对象 ？这个对象还存在疑问，有的地方认为此对象为被代理对象  已经确定此对象为代理对象
 *      Method 被代理对象的方法对象
 *      Object[] 被代理对象方法的参数
 *      MethodProxy 代理对象发方法对象
 *
 *      执行原方法体：
 *
 *      在执行原方法体时为什么不能使用methodProxy.invokeSuper(userDao, objects)？methodProxy对象不是代理对象发方法对象吗？
 *      代理对象不是被代理对象的子类吗？
 *
 *
 *
 *
 *
 *
 */
public class CustomCglibProxyTest {

    public static void main(String[] args) {
        UserDao userDao = getUserDao();
        String save = userDao.save();
        System.out.println(save);
        userDao.update();
    }

    public static UserDao getUserDao(){
        final UserDao userDao = new UserDao();
        Enhancer enhancer = new Enhancer();
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                String methodProxyName = methodProxy.getSuperName();
                String methodName = method.getName();
                String superName = methodProxy.getSuperName();
                System.out.println(methodName);
                System.out.println(methodProxyName);
                System.out.println(superName);
                if("save".equals(methodName)){
                    System.out.println("执行代理业务");
                    return "代理成功";
                }else{
                    //这里使用invoke，不使用invokeSupper的原因？
//                    Object invokeSuper = methodProxy.invokeSuper(userDao, objects);
                    return method.invoke(userDao,objects);
                }
            }
        });
        enhancer.setSuperclass(userDao.getClass());
        return (UserDao) enhancer.create();
    }
}
